"""
行情数据管理器：处理实时行情订阅和历史数据获取
"""
import time
import pandas as pd
from typing import Dict
from datetime import date
from xtquant import xtdata
from config.config import ConfigManager
from .exceptions import MarketDataError
from utils.logger import sys_logger

xtdata.enable_hello = False

logger = sys_logger.getChild('Market')

class MarketDataManager:
    def __init__(self, config: ConfigManager):
        """
        初始化行情管理器
        :param symbols: 订阅的标的列表
        """
        self._engine = None
        self._config = config

        self._history_data: Dict[str, pd.DataFrame] = {}   # 各标的的历史股价数据
        self._financial_data: Dict[str, pd.DataFrame] = {} # 各标的的历史财务数据

        self.done = False

    def bind(self, engine):
        self._engine = engine

    def get_index_symbols(self, index: str):
        # print(f"xtdata.get_stock_list_in_sector(index)={xtdata.get_stock_list_in_sector('沪深A股')}")
        # xtdata.download_sector_data()
        return xtdata.get_stock_list_in_sector(index)

    def load_history_k_day_data(self, symbol: str, data: pd.DataFrame) -> None:
        """加载标的的历史股价数据
        :param symbol: 标的代码
        :param data: 包含DatetimeIndex的DataFrame（需有close字段）
        """
        if not isinstance(data.index, pd.DatetimeIndex):
            raise ValueError("历史股价数据索引必须是DatetimeIndex")

        self._history_data[symbol] = data.sort_index(ascending=True)
        logger.debug("加载%s标的历史股价数据 | 时间范围: %s ~ %s | 数据量: %d",
                   symbol, data.index[0].date(), data.index[-1].date(), len(data))

    def load_financial_data(self, symbol: str, data: pd.DataFrame) -> None:
        """加载标的的历史财务数据
        :param symbol: 标的代码
        :param data: 包含DatetimeIndex的DataFrame（需有close字段）
        """
        if not isinstance(data.index, pd.DatetimeIndex):
            raise ValueError("历史财务数据索引必须是DatetimeIndex")

        self._financial_data[symbol] = data.sort_index(ascending=True)
        logger.debug("加载%s标的历史财务数据 | 时间范围: %s ~ %s | 数据量: %d",
                   symbol, data.index[0].date(), data.index[-1].date(), len(data))

    def get_latest_data(self, symbols: list):
        """
        获取最新股票数据
        :param symbol: 标的代码
        :return: 包含最新数据的dict
        """

        try:
            # 下载数据
            logger.info("开始下载最新股票数据")
            data = xtdata.get_full_tick(symbols)

            return data

        except Exception as e:
            logger.error("Failed to download latest data: {str(e)}")
            raise MarketDataError("Latest data download failed") from e

    def download_history_data(self, symbols: list, start_date: date, end_date: date):
        """
        获取历史K线数据
        :param symbol: 标的代码
        :param start: 开始日期 (YYYYMMDD)
        :param end: 结束日期 (YYYYMMDD)
        :return: 包含OHLCV数据的表格
        """

        # 数据格式转换
        start = start_date.strftime('%Y%m%d')
        end   = end_date.strftime('%Y%m%d')

        # 下载完成标记
        self.done = False

        # 回调函数
        def on_progress(data):
            logger.debug(data)
            finished = data['finished']
            total = data['total']

            print(f"\r下载历史数据进度: {finished}/{total}", end="", flush=True)

            if finished >= total:
                self.done = True

        try:
            # 下载数据
            logger.info(f"开始下载历史数据: {start}~{end}")
            xtdata.download_history_data2(
                stock_list=symbols,
                period='1d',
                start_time=start,
                end_time=end,
                callback=on_progress
            )

            # 等待下载完成
            while not self.done:
                time.sleep(1)

            print('', flush=True)

            # 加载数据
            for idx, symbol in enumerate(symbols):
                df = self.get_history_data(symbol, start_date, end_date)

                if not df.empty:
                    #数据清洗
                    data = df[df['volume'] != 0]

                    self.load_history_k_day_data(symbol, data)
                    print(f"\r加载历史股价数据进度: {idx+1}/{len(symbols)}", end="", flush=True)

            print('', flush=True)

        except Exception as e:
            logger.error("Failed to download history data: {str(e)}")
            raise MarketDataError("History data download failed") from e

    def get_history_data(self, symbol: str, start_date: date, end_date: date):
        """
        获取历史K线数据
        :param symbol: 标的代码
        :param start: 开始日期 (YYYYMMDD)
        :param end: 结束日期 (YYYYMMDD)
        :return: 包含OHLCV数据的表格
        """

        # 数据格式转换
        start = start_date.strftime('%Y%m%d')
        end   = end_date.strftime('%Y%m%d')

        try:
            # 获取数据
            data = xtdata.get_market_data(
                field_list=['open', 'high', 'low', 'close', 'volume'],
                stock_list=[symbol],
                period='1d',
                dividend_type='front_ratio',
                start_time=start,
                end_time=end
            )

            # 将每个DataFrame的行合并成一个大的DataFrame
            df = pd.concat(data.values(), axis=0).T
            df.columns = data.keys()
            df.index = pd.to_datetime(df.index)
            df.index.name = 'date'
            df = df.sort_index(ascending=True)

            if not df.empty:
                # 成功日志（包含关键信息）
                logger.debug(
                    f"成功获取{symbol}历史数据 | 时间范围: {start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')} | "
                    f"数据量: {len(df)}条 | 最新日期: {df.index[-1].strftime('%Y-%m-%d')}"
                )

                logger.debug(f"数据样例 head:\n{df.head(5)}")  # 调试日志显示前5行

                logger.debug(f"数据样例 tail 3:\n{df.tail(3)}")  # 调试日志显示后3行

            else:
                logger.warning(
                    f"无法获取{symbol}历史K线数据 | 时间范围: {start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
                )

            return df

        except Exception as e:
            logger.error(f"Failed to get history data for {symbol}: {str(e)}")
            raise MarketDataError(f"History data get failed for {symbol}") from e

    def get_local_history_data(self, symbol: str, start_date: date, end_date: date):
        """
        从本地获取历史K线数据
        :param symbol: 标的代码
        :param start: 开始日期 (YYYYMMDD)
        :param end: 结束日期 (YYYYMMDD)
        :return: 包含OHLCV数据的表格
        """

        try:
            df = pd.DataFrame()

            hist_data = self._history_data.get(symbol)

            if not (hist_data is None or hist_data.empty):
                df = hist_data
                df = df[(df.index >= pd.to_datetime(start_date)) & (df.index <= pd.to_datetime(end_date))].copy()

            return df

        except Exception as e:
            logger.error(f"Failed to get local history data for {symbol}: {str(e)}")
            raise MarketDataError(f"Local history data get failed for {symbol}") from e


    def download_financial_data(self, symbols: list, start_date: date, end_date: date):
        # 数据格式转换
        start = start_date.strftime('%Y%m%d')
        end   = end_date.strftime('%Y%m%d')

        # 下载完成标记
        self.done = False

        # 回调函数
        def on_progress(data):
            logger.debug(data)

            finished = data['finished']
            total = data['total']

            print(f"\r下载财务数据进度 {finished}/{total} ", end="", flush=True)

            if finished >= total:
                self.done = True

        try:
            # 下载财务数据
            logger.debug(f"开始下载历史财务数据: {start}~{end}")

            financial_table_list = ['Capital']

            xtdata.download_financial_data2(
                stock_list = symbols,
                table_list = financial_table_list,
                start_time = start,
                end_time = end,
                callback = on_progress
            )

            # 等待下载完成
            while not self.done:
                time.sleep(1)

            print('', flush=True)

            for idx, symbol in enumerate(symbols):
                df = self.get_financial_data(symbol, start_date, end_date)

                if not df.empty:
                    #数据清洗
                    data = df[df['total_capital'] != 0]

                    self.load_financial_data(symbol, data)
                    print(f"\r加载历史财务数据进度: {idx+1}/{len(symbols)} ", end="", flush=True)

            print('', flush=True)

        except Exception as e:
            logger.error("Failed to download financial data: {str(e)}")
            raise MarketDataError("financial data download failed") from e

    def get_financial_data(self, symbol: str, start_date: date, end_date: date):
        """
        获取历史财务数据
        :param symbol: 标的代码
        :param start: 开始日期 (YYYYMMDD)
        :param end: 结束日期 (YYYYMMDD)
        :return: 包含历史财务数据的表格
        """

        # 数据格式转换
        start = start_date.strftime('%Y%m%d')
        end   = end_date.strftime('%Y%m%d')

        try:
            # 下载财务数据
            logger.debug(f"开始获取{symbol}历史财务数据: {start}~{end}")

            financial_table_list = ['Capital']

            # 获取财务数据
            data = xtdata.get_financial_data(
                stock_list = [symbol],
                table_list = financial_table_list,
                start_time = start,
                end_time = end
            )

            df = data[symbol]['Capital']

            if not df.empty:
                #提取关键参数
                df = df[['m_timetag', 'total_capital']].copy()
                df['m_timetag'] = pd.to_datetime(df['m_timetag'], format='%Y%m%d')
                df = df.rename(columns={'m_timetag': 'date'}).set_index('date').sort_index().copy()

                # 成功日志（包含关键信息）
                logger.debug(
                    f"成功获取{symbol}历史财务数据 | 时间范围: {start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')} | "
                    f"数据量: {len(df)}条 | 最新日期: {df.index[-1].strftime('%Y-%m-%d')}"
                )

                logger.debug(f"数据样例 head:\n{df.head(5)}")  # 调试日志显示前5行
                logger.debug(f"数据样例 tail 3:\n{df.tail(3)}")  # 调试日志显示后3行

            else:
                logger.warning(
                    f"无法获取{symbol}历史财务数据 | 时间范围: {start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
                )

            return df

        except Exception as e:
            logger.error(f"Failed to get financial data for {symbol}: {str(e)}")
            raise MarketDataError(f"financial data get failed for {symbol}") from e

    def get_local_financial_data(self, symbol: str, start_date: date, end_date: date):
        """
        获取历史财务数据
        :param symbol: 标的代码
        :param start: 开始日期 (YYYYMMDD)
        :param end: 结束日期 (YYYYMMDD)
        :return: 包含历史财务数据的表格
        """

        # 数据格式转换

        try:
            df = pd.DataFrame()

            fin_data = self._financial_data.get(symbol)

            if not (fin_data is None or fin_data.empty):
                df = fin_data
                df = df[(df.index >= pd.to_datetime(start_date)) & (df.index <= pd.to_datetime(end_date))].copy()

            return df

        except Exception as e:
            logger.error(f"Failed to get local financial data for {symbol}: {str(e)}")
            raise MarketDataError(f"Local financial data get failed for {symbol}") from e